package com.dstation.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dstation.dao.RecommendInfoMapper;
import com.dstation.domain.*;
import com.dstation.service.interf.IRecommendService;
import com.dstation.utils.Constants;
import com.dstation.utils.RecommendStrategyUtil;
import com.dstation.utils.RedisPreKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;

@Service
@Slf4j
public class RecommendServiceImpl  implements IRecommendService {

    final  int pageSize=10;
    @Autowired
    private RedisTemplate redisTemplate;
    @Resource
    private JedisPool redisPoolFactory;

    @Resource
    private RecommendInfoMapper recommendMapper;

    @Override
    public boolean addBrowserData() {
        return recommendMapper.insertBrowserData(RecommendStrategyUtil.BROWSER_REWARD)>0;
    }

    @Override
    public boolean addCollectData() {
        return recommendMapper.insertCollectData(RecommendStrategyUtil.COLLECT_REWARD)>0;
    }

    @Override
    public boolean addLikedData() {
        return recommendMapper.insertLikedData(RecommendStrategyUtil.LIKED_REWARD)>0;
    }

    @Override
    public boolean addCoinData() {
        return recommendMapper.insertCoinData(RecommendStrategyUtil.COIN_REWARD)>0;
    }

    @Override
    public boolean dropAllRecommendData() {
        return recommendMapper.deleteAllRecommendData()>0;
    }

    @Override
    public List<RecommendInfo> findAllRecommend() {
        return recommendMapper.selectAllRecommend();
    }

    @Override
    public List<VideoInfo> findAllVideo() {
        return recommendMapper.selectAllVideo();
    }

    @Override
    public void simlarRecForUserRandom(MqMessage message, int browserClick) {
        Long objectId=message.getHandleObjectId();

        if(Objects.isNull(objectId)){
            return ;
        }

        try {

            //获取用户相似度数据，取前六十条（满配）
            List<Object> items=new ArrayList<>(redisTemplate.boundZSetOps(RedisPreKey.SIMILAR_REC_DATA+objectId).range(0L,60L));


            String rec_key=RedisPreKey.ALS_OFFLINE_REC_DATA+message.getUserId();

            //获取个人离线推荐数据
            List<Object> person=new ArrayList<>(redisTemplate.boundZSetOps(rec_key).range(0L,300L));

            if(items.size()>1){
                int upTemplete=Constants.BROWSER_CLICK;

                //生成随机位置替换  依赖头部效应制定规则
                int[] position=getRandomPosition(upTemplete);

                for(int i=0;i<Math.min(items.size()/ Constants.BROWSER_CLICK,person.size()/pageSize);i++){

                    for(int j=0;j<position.length;j++){
                        List list = new ArrayList(redisTemplate.boundZSetOps(rec_key).rangeByScore(i*pageSize+position[j],i*pageSize+position[j]));;
                        if(list==null||list.size()==0){
                            //若其位置无数据，直接添加
                            redisTemplate.boundZSetOps(rec_key).add(items.get(i*upTemplete+j),i*pageSize+position[j]);
                        }else{
                            //该位置上有数据则，先删除后插入
                            redisTemplate.boundZSetOps(rec_key).remove(list.get(0));

                            redisTemplate.boundZSetOps(rec_key).add(items.get(i*upTemplete+j),i*pageSize+position[j]);
                        }
                    }

                }

            }



        }catch (Exception e){
            log.error("实时推荐分配数据失败", e);
            return ;
        }

    }

    @Override
    public IPage<VideoInfo> findRecommendVideo(UserInfo userInfo, Page page){

//        Set set = redisTemplate.boundZSetOps(RedisPreKey.ALS_OFFLINE_REC_DATA + userInfo.getUserId()).range(0L, 300L);
        List<Integer> idSet=null;
        IPage<VideoInfo> res=null;
        //用户尚未登陆
        if(Objects.isNull(userInfo)){

            List<Integer> hotData=new ArrayList(zrange(RedisPreKey.HOT_RECOMMEND_DATA,0,-1));

            res=recommendMapper.selectRecommendVideo(hotData,page);



        }else{
            idSet = new ArrayList(zrange(RedisPreKey.ALS_OFFLINE_REC_DATA + userInfo.getUserId(), 0, -1));


            res=recommendMapper.selectRecommendVideo(idSet,page);

            //对用户个性数据不足的情况进行补足
            if(idSet.size()<100){
                int cur=100-idSet.size();
                int index=0;
                List<Integer> hotData=new ArrayList(zrange(RedisPreKey.HOT_RECOMMEND_DATA,0,-1));

                IPage<VideoInfo> s1=recommendMapper.selectRecommendVideo(hotData,page);

                List<VideoInfo> r1 = res.getRecords();
                List<VideoInfo> r2 = s1.getRecords();

                r1.addAll(r2);
                res.setRecords(r1);

            }

        }
        return res;
    }

    @Override
    public List<HistoryInfo> findHotBrowser(Timestamp deadLine) {
        return recommendMapper.selectHotBroswerData(deadLine);
    }

    @Override
    public List<VideoLikedInfo> findHotLiked(Timestamp deadLine) {
        return recommendMapper.selectHotLikedData(deadLine);
    }

    @Override
    public List<CollectionInfo> findHotCollection(Timestamp deadLine) {
        return recommendMapper.selectHotCollectData(deadLine);
    }

    @Override
    public List<CoinOperatedInfo> findHotCoin(Timestamp deadLine) {
        return recommendMapper.selectHotCoinData(deadLine);
    }

    private int[] getRandomPosition(int count) {
        Random random=new Random();
        int[] res=new int[count];
        Set set=new HashSet();


        for(int i=0;i<count;i++){
            res[i]=random.nextInt(pageSize/2)+1;
            set.add(res[i]);
        }



        return res;
    }

    public  Set<String> zrange(String key, long start, long stop) {
        Set<String> value = null;
        JedisPool pool = null;
        Jedis jedis = null;

        try {

            jedis = redisPoolFactory.getResource();
            value = jedis.zrange(key,start,stop);
        } catch (Exception var8) {
            log.error("Redis的zrange操作错误", var8);
        } finally {
        }

        return value;
    }
}
